import random
import struct
import hashlib


class TlvBuilder(object):
    def __init__(self, data={}):
        self.tlv_ver = data.get("ver", 2)
        self.tlv_type = data.get("type", 0)
        self.tlv_pap_chap = data.get("pap_chap", 1)
        self.tlv_rsvd = data.get("rsvd", 0)
        self.tlv_serial_no = data.get("serial_no", 0)
        self.tlv_req_id = data.get("req_id", 0)
        self.tlv_user_ip = data.get("user_ip", "0.0.0.0")
        self.tlv_user_port = data.get("user_port", 0)
        self.tlv_err_code = data.get("err_code", 0)
        self.tlv_attr = data.get("attr", {})
        self.tlv_secret = data.get("secret", "")
        self.tlv_user_ip_arr = self.__ip_parser()
        self.tlv_attr_num = len(self.tlv_attr)

    def change_attr(self, data={}):
        self.tlv_ver = data.get("ver", self.tlv_ver)
        self.tlv_type = data.get("type", self.tlv_type)
        self.tlv_pap_chap = data.get("pap_chap", self.tlv_pap_chap)
        self.tlv_rsvd = data.get("rsvd", self.tlv_rsvd)
        self.tlv_serial_no = data.get("serial_no", self.tlv_serial_no)
        self.tlv_req_id = data.get("req_id", self.tlv_req_id)
        self.tlv_user_ip = data.get("user_ip", self.tlv_user_ip)
        self.tlv_user_port = data.get("user_port", self.tlv_user_port)
        self.tlv_err_code = data.get("err_code", self.tlv_err_code)
        self.tlv_attr = data.get("attr", self.tlv_attr)
        self.tlv_secret = data.get("secret", self.tlv_secret)
        self.tlv_user_ip_arr = self.__ip_parser()
        self.tlv_attr_num = len(self.tlv_attr)

    def attr_print(self):
        print_str = "ver:%s\ntype:%s\npap_chap:%s\nrsvd:%s\nserial_no:%s\nreq_id:%s\nuser_ip:%s\nuser_port:%s\nerr_code:%s\nattr:%s\nsecret:%s"
        print(print_str % (
            self.tlv_ver, self.tlv_type, self.tlv_pap_chap, self.tlv_rsvd, self.tlv_serial_no, self.tlv_req_id,
            self.tlv_user_ip, self.tlv_user_port, self.tlv_err_code, self.tlv_attr,
            self.tlv_secret))

    # data{"username":zyt,"pwd":"123456"} secret = "123456789"
    def get_online_data(self):
        self.tlv_type = 3
        return self.build_data()

    def get_offline_data(self):
        self.tlv_type = 5
        return self.build_data()

    def build_data(self):
        # 本机IP
        # user_ip = self.ip_parser(socket.gethostbyname(socket.gethostname()))
        auth = self.__create_auth()
        result = self.__create_data(auth)
        return result

    def __create_auth(self):
        # fmt = "BBBBHHBBBBHBBQQBB" + str(dLen1 - 2) + "sBB" + str(dLen2 - 2) + "s" + str(sLen) + "s"
        fmt = self.__create_auth_fmt()
        data = self.__create_auth_value_list()
        # auth = self.__create_md5_auth(
        #     struct.pack(fmt, self.tlv_ver, self.tlv_type, self.pap_chap, self.rsvd, self.tlv_serial_no, self.req_id,
        #                 int(user_ip[0]),
        #                 int(user_ip[1]), int(user_ip[2]), int(user_ip[3]), self.user_port, self.err_code,
        #                 self.tlv_attr_num, 0,
        #                 0, 1, dLen1, data["username"].encode("utf-8"), 2, dLen2, data["pwd"].encode("utf-8"),
        #                 secret.encode("utf-8")))
        # print(data)
        auth = self.__create_md5_auth(struct.pack(fmt, *data))
        print("auth:%s" % auth)
        return auth

    def __create_auth_fmt(self):
        fmt = "BBBBHHBBBBHBBQQ"
        for i in self.tlv_attr:
            fmt += "BB%ss" % str(len(self.tlv_attr[i].encode("utf-8")))
        fmt += "%ss" % str(len(self.tlv_secret))
        print("auth_fmt:%s" % fmt)
        return fmt

    def __create_auth_value_list(self):
        auth_value_list = self.__create_value_list_head()
        auth_value_list.append(0)
        auth_value_list.append(0)
        for i in self.tlv_attr:
            if i == "username":
                auth_value_list.append(1)
            elif i == "password":
                auth_value_list.append(2)
            elif i == "challenge":
                auth_value_list.append(3)
            elif i == "chappassword":
                auth_value_list.append(4)
            auth_value_list.append(len(self.tlv_attr[i].encode("utf-8")) + 2)
            auth_value_list.append(self.tlv_attr[i].encode("utf-8"))
        auth_value_list.append(self.tlv_secret.encode("utf-8"))
        return auth_value_list

    def __create_value_list_head(self):
        value_list = []
        value_list.append(self.tlv_ver)
        value_list.append(self.tlv_type)
        value_list.append(self.tlv_pap_chap)
        value_list.append(self.tlv_rsvd)
        value_list.append(self.tlv_serial_no)
        value_list.append(self.tlv_req_id)
        for i in self.tlv_user_ip_arr:
            value_list.append(int(i))
        value_list.append(self.tlv_user_port)
        value_list.append(self.tlv_err_code)
        value_list.append(self.tlv_attr_num)
        return value_list

    def __create_data(self, auth):
        # fmt = "BBBBHHBBBBHBB16sBB" + str(dLen1 - 2) + "sBB" + str(dLen2 - 2) + "s"
        fmt = self.__create_data_fmt()
        data = self.__create_data_value_list(auth)
        # result = struct.pack(fmt, self.tlv_ver, self.tlv_type, self.pap_chap, self.rsvd, self.tlv_serial_no,
        #                      self.req_id,
        #                      int(user_ip[0]),
        #                      int(user_ip[1]), int(user_ip[2]), int(user_ip[3]),
        #                      self.user_port, self.err_code, self.tlv_attr_num, auth, 1, dLen1,
        #                      data["username"].encode("utf-8"), 2, dLen2, data["pwd"].encode("utf-8"))
        result = struct.pack(fmt, *data)
        print("data:%s" % result)
        return result

    def __create_data_fmt(self):
        fmt = "BBBBHHBBBBHBB16s"
        for i in self.tlv_attr:
            fmt += "BB%ss" % str(len(self.tlv_attr[i].encode("utf-8")))
        print("data_fmt:%s" % fmt)
        return fmt

    def __create_data_value_list(self, auth):
        auth_value_list = self.__create_value_list_head()
        auth_value_list.append(auth)
        for i in self.tlv_attr:
            if i == "username":
                auth_value_list.append(1)
            elif i == "password":
                auth_value_list.append(2)
            elif i == "challenge":
                auth_value_list.append(3)
            elif i == "chappassword":
                auth_value_list.append(4)
            auth_value_list.append(len(self.tlv_attr[i].encode("utf-8")) + 2)
            auth_value_list.append(self.tlv_attr[i].encode("utf-8"))
        return auth_value_list

    def __create_md5_auth(self, data):
        m = hashlib.md5()
        m.update(data)
        return m.digest()

    def __ip_parser(self):
        result = [0, 0, 0, 0]
        if self.tlv_user_ip.split is not None and self.tlv_user_ip.split != "":
            result = self.tlv_user_ip.split('.')
        return result

    def tlv_result_parser(self, data):
        result = False
        if data[14] == 4:
            result = True
        return result


if __name__ == "__main__":
    data = {"type": 3, "serial_no": 22080, "user_ip": "192.168.1.190",
            "attr": {"username": "zyt", "password": "123456"}, "secret": "123456789"}
    # data["username"] = "zyt"
    # data["pwd"] = "123456"
    # secret = "123456789"
    # print(TlvParse().get_online_data(data, secret))
    # tb = TlvBuilder()
    # tb.attr_print()
    # a = {"username": "zyt", "pwd": "123456"}
    # data = {"attr": a, "secret": "123456"}
    tb = TlvBuilder(data)
    # tb.attr_print()
    print(tb.build_data())
    # tb.test(*data)
